//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <bulverde.h>
#include "misc.h"

int cprintf(const char *, ...);

#define CLK_I2C_ENABLE (CKEN|=CKEN14_I2C)
#define CLK_I2C_DISABLE (CKEN&=~CKEN14_I2C)

#define I2C_SCL_GPIO117	(1<<21)
#define I2C_SDA_GPIO118 (1<<22)
#define I2CPERIOD   4
#define CAMERA_I2CWRITE_ADDR   0x60
#define CAMERA_I2CREAD_ADDR    0x61
#define I2C_MAX_XFER_WAIT      0x1000
#define I2C_MAX_BUS_WAIT       0x1000

EXTERN_C void I2C_GPIO(void)
{
//    GAFR3_U &= ~((3<<10)|(3<<12));
    GAFR3_U |= (1<<10)|(1<<12);
    //GPDR3 |= I2C_SCL_GPIO117|I2C_SDA_GPIO118;
	//GPSR3 |= I2C_SCL_GPIO117|I2C_SDA_GPIO118;
}

//static void I2C_Write(unsigned char* pData, unsigned long dwLen)
EXTERN_C void I2C_Write(unsigned char* pData, unsigned long dwLen)
{
    return;
}

EXTERN_C void I2C_Read(unsigned char * pData, unsigned long dwLen)
{
    return;
}

EXTERN_C void I2C_RW(unsigned char addr1, unsigned char addr2, unsigned char * pData, unsigned long dwLen)
{
    return;
}

EXTERN_C void I2C_enable(void)
{
	BV_ISAR = 0;      // Slave Address
	BV_ICR = I2C_ICR_GCD | I2C_ICR_IUE | I2C_ICR_SCLEA; /*100 kbps*/
  	//BV_ICR = I2C_ICR_GCD | I2C_ICR_IUE | I2C_ICR_SCLEA | (1<<15)/*400 kbps*/;
}

EXTERN_C void I2C_Initial(void)
{
    CLK_I2C_ENABLE;      //enable i2c clock
	I2C_GPIO();
    I2C_enable();
}

EXTERN_C void I2C_Disable(void)
{
  	BV_ICR &= ~I2C_ICR_IUE; // Disable I2C Unit

    CLK_I2C_DISABLE;
}

static int I2C_wait_for_tx(void)
{
    int retry = I2C_MAX_XFER_WAIT;

    while(((BV_ISR & I2C_ISR_ITE)==0)&&(retry--))
    {
	    DzDelay(100);       // sleep 100 milisecond
	    //cprintf("I2C ISR :%x\r\n",ISR);
    }

    if (retry < 0)
    {
	    cprintf("Timeout waiting for tx \r\n");
    }
	else{
		BV_ISR = I2C_ISR_ITE;
		(void)BV_ISR;
	}
    return ((retry<0) ? -1 : 0);
}

static int I2C_wait_for_rx(void)
{
    int retry = I2C_MAX_XFER_WAIT;

    while((!(BV_ISR & I2C_ISR_IRF))&& (retry--))
    {
	    DzDelay(100);
    }

    if (retry < 0)
    {
	    cprintf("Timeout waiting for rx \n");
    }
    else{
	    BV_ISR = I2C_ISR_IRF;
	    (void) BV_ISR;
    }
    return ((retry<0) ? -1 : 0);
}

static int I2C_wait_for_bus(void)
{
    int retry = I2C_MAX_BUS_WAIT;
    unsigned long isr = BV_ISR;
    while ( (isr & I2C_ISR_IBB) && (isr & I2C_ISR_UB) && retry--)
    {
	    DzDelay(100);
	    isr = BV_ISR;
    }

    if (retry <0)
    {
	    cprintf("Timeout waiting for bus busy \n");
    }
    return ((retry<0) ? -1 : 0);
}

struct i2c_msg {
    char addr;
    char flags;
    char *buf;
    int len;
};

#define I2C_M_RD 1
EXTERN_C int I2C_transfer(struct i2c_msg msg[], int num)
{
    int ret=0;
    int addr;
    struct i2c_msg *pmsg = msg;

    ret  = I2C_wait_for_bus();

    if(ret)
    {
	    cprintf("bus busy\r\n");
	    goto out;
    }

    while(num--)
    {
	addr = pmsg->addr ;
	if (pmsg->flags & I2C_M_RD)
	{
	    addr |=1;
	}
	else
	{
	    addr &= ~1;
	}

//address of slave
	BV_IDBR = addr;
//initiate write
	BV_ICR &= ~(I2C_ICR_STOP);
	BV_ICR |= (I2C_ICR_START | I2C_ICR_TB);

	ret = I2C_wait_for_tx();
	if(ret < 0)
	{
	    cprintf ("init tx time out \r\n");
	    goto out;
	}
//start to transfer
	if (pmsg->flags & I2C_M_RD) //read bytes
	{
	    int count;

		BV_ICR &= (~(I2C_ICR_START | I2C_ICR_STOP));

	    for(count=0 ; count<pmsg->len; count++)
	    {
		if (count+1 == pmsg->len)
		{
			//last byte to read
		    BV_ICR |= ( I2C_ICR_STOP | I2C_ICR_TB| I2C_ICR_ACKNAK);
		}
		else
		{
		    BV_ICR |= (I2C_ICR_TB);/* Read */
		}

		/*
		while((ISR&ISR_IRF) == 0){}

		ISR = ISR_IRF;
		(void) ISR;

	*/
		ret = I2C_wait_for_rx();

		if(ret)
		{
		    cprintf("i2c_read: timeout\r\n");
		    goto out;
		}
		pmsg->buf[count]=(char)BV_IDBR;

		(BV_ICR) &=~ ( I2C_ICR_ACKNAK );

	    }


	}
	else //write bytes
	{
	    int count;

	    for(count=0;count<pmsg->len;count++)
	    {

		BV_IDBR=pmsg->buf[count];

		BV_ICR &= (~(I2C_ICR_START|I2C_ICR_STOP));

		if (count+1 == pmsg->len)
		{
		    BV_ICR |= (I2C_ICR_TB|I2C_ICR_STOP);
		}
		else{
		    BV_ICR |= (I2C_ICR_TB);
		}
	/*
		while((ISR&ISR_ITE) == 0){}

		ISR = ISR_ITE;
		(void) ISR;
	*/

		ret = I2C_wait_for_tx();
		if(ret<0)
		{
		    cprintf("i2c_write: timeout\r\n");
		    goto out;
		}

	    }

	}
	pmsg += 1;
    }

	 // while( (ISR & ISR_IBB) || (ISR & ISR_UB) ) { ; }
 out:
    return ret;
}


EXTERN_C int I2C_master_send(const char * pbuf, int count)
{
  int ret;
  struct i2c_msg msg;

  msg.addr = (char)CAMERA_I2CWRITE_ADDR;
  msg.flags = 0;
  msg.buf = (char*)pbuf;
  msg.len = count;

  ret = I2C_transfer(&msg, 1);
  return ret;
}

EXTERN_C int I2C_master_recv(char * pbuf, int count)
{
  int ret;
  struct i2c_msg msg;

  msg.addr = (char)CAMERA_I2CREAD_ADDR;
  msg.flags = I2C_M_RD;
  msg.buf = pbuf;
  msg.len = count;

  ret = I2C_transfer(&msg, 1);
  return ret;
}


EXTERN_C int  I2C_write_byte(char regaddr,char val)
{
   char buf[8];
    buf[0] = regaddr;
    buf[1] = val;
    return I2C_master_send(buf,2);
}

EXTERN_C int  I2C_read_byte(char regaddr,char *buf)
{
   char addbuf[2];

    addbuf	[0] = regaddr;
    if( I2C_master_send(addbuf,1) )
    {
            cprintf("i2c send address fail\r\n");
	     return -1;
    }
    if( I2C_master_recv(buf,1) )
    {
            cprintf("i2c receive  address fail\r\n");
	     return -1;
    }
    return 0;
}

//void SET_I2C_DATA_H()
//{
//    GPSR3 |= I2C_SDA_GPIO118;     //pull up the I2C_SDA_GPIO118
//}
//
//void SET_I2C_DATA_L()
//{
//    GPCR3 |= I2C_SDA_GPIO118;     //pull down the I2C_SDA_GPIO118
//}
//
//void SET_I2C_CLK_H()
//{
//    GPSR3 |= I2C_SCL_GPIO117;     //pull up the I2C_SCL_GPIO117
//}
//
//void SET_I2C_CLK_L()
//{
//    GPCR3 |= I2C_SCL_GPIO117;     //pull down the I2C_SCL_GPIO117
//}
//
//void SET_I2C_DATA_INPUT()
//{
//    GPDR3 &= ~I2C_SDA_GPIO118;    //set I2C_SDA_GPIO118 in
//}
//
//unsigned int I2C_ACKNOWLEDGE()
//{
//    unsigned int status;
//	status = GPLR3;
//    return status;
//}
//
//void SET_I2C_DATA_OUTPUT()
//{
//    GPDR3 |= I2C_SDA_GPIO118;     //set I2C_SDA_GPIO118 out
//}
//
// /*******************************************************************************
// * i2c_start
// *******************************************************************************/
//void i2c_start(void)
//{
//    DzDelay(I2CPERIOD);
//    SET_I2C_DATA_H();
//
//    DzDelay(I2CPERIOD);
//    SET_I2C_CLK_H();
//
//    DzDelay(I2CPERIOD);
//    SET_I2C_DATA_L();
//
//    DzDelay(I2CPERIOD);
//    SET_I2C_CLK_L();
//}
//
///*******************************************************************************
// * i2c_stop
// *******************************************************************************/
//void i2c_stop(void){
//
//	SET_I2C_DATA_L();
//    DzDelay(I2CPERIOD);
//
//	SET_I2C_CLK_H();
//    DzDelay(I2CPERIOD);
//
//	SET_I2C_DATA_H();
//    DzDelay(I2CPERIOD);
//}
//
///*******************************************************************************
// * i2c_read_core
// *   Type :	void
// *   Ret val :	unsigned char
// *   Argument :	void input clk=h data as input
// *		when output, clk=h	data as input
// *   Function :
// *******************************************************************************/
//unsigned char i2c_read_core(void)
//{
//	unsigned char ucCnt, ucShift, ucData;
//	unsigned int ucTemp;
//
//	ucShift = 0x80;
//	ucData = 0x0;
//	SET_I2C_DATA_INPUT();
//
//	for (ucCnt=0;ucCnt<8;ucCnt++)
//	{
//        DzDelay(I2CPERIOD);
//		SET_I2C_CLK_H();
//
//        DzDelay(I2CPERIOD);
//		ucTemp = I2C_ACKNOWLEDGE();
//		if(ucTemp & I2C_SDA_GPIO118)
//		{
//			ucData |= ucShift;
//		}
//		ucShift=ucShift >> 1;
//
//        DzDelay(I2CPERIOD);
//		SET_I2C_CLK_L();
//	}
//
//    DzDelay(I2CPERIOD);
// 	SET_I2C_DATA_OUTPUT();
//	return ucData;
//}
//
//int i2c_write_core(unsigned char ucData)
//{
//	unsigned char 	ucCnt,ucShift;
//	ucShift = 0x80;
//
//	for (ucCnt=0;ucCnt<8;ucCnt++)
//	{
//		if (ucData&ucShift)
//		{
//			SET_I2C_DATA_H();
//		}
//		else
//		{
//			SET_I2C_DATA_L();
//		}
//		ucShift = ucShift>>1;
//
//        DzDelay(I2CPERIOD);
//		SET_I2C_CLK_H();
//
//        DzDelay(I2CPERIOD);
//		SET_I2C_CLK_L();
//        DzDelay(I2CPERIOD);
// 	}
//
// 	return 1;
//}
//
///*******************************************************************************
// * i2c_byte_read
// *   Type :	void
// *   Ret val :	none
// *   Argument :
// *		unsigned char ucAddr		the address
// *		unsigned char ucData		written data
// *   Function :
// *******************************************************************************/
//int i2c_byte_read(unsigned char ucAddr,unsigned char *rtnData)
//{
//	unsigned char ucGetData;
//
//	// start signal
//	i2c_start();
//
//	// write control data
//	if( i2c_write_core(CAMERA_I2CWRITE_ADDR) == 0 )
//	{
//        return  0;
//	}
//
// 	// write address
// 	if( i2c_write_core(ucAddr) == 0)
// 	{
//        return 0;
// 	}
//
//	// stop signal
//	i2c_stop();
//
//	// start signal
//    i2c_start();
//
//	// write control read
// 	if( i2c_write_core(CAMERA_I2CREAD_ADDR) == 0 )
// 	{
//        return 0;
// 	}
//
// 	// read data
// 	ucGetData = i2c_read_core();
//
//	// Stop signal
//	i2c_stop();
//
//	*rtnData = ucGetData;
//	return  1;
//}
//
//int i2c_byte_write(unsigned char ucAddr, unsigned char ucData)
//{
//    // start signal
//	i2c_start();
//
//    // write control data
//	if(i2c_write_core(CAMERA_I2CWRITE_ADDR) == 0)
//	{
//	    return 0;
//	}
//
//    // write address
// 	if(i2c_write_core(ucAddr) == 0)
// 	{
// 	    return 0;
// 	}
//
//    // read data
//	if(i2c_write_core(ucData) == 0)
//	{
//	    return 0;
//	}
//
//    // Stop signal
//	i2c_stop();
//	return 1;
//}
//
//int i2c_buffer_write(unsigned char ucAddr, unsigned char *ucData,short count)
//{
//    short i;
//	i2c_start();
//
//	if(i2c_write_core(CAMERA_I2CWRITE_ADDR) == 0)
//	{
//	    return 0;
//	}
//
// 	if(i2c_write_core(ucAddr) == 0)
// 	{
// 	    return 0;
// 	}
//
//	for(i=0; i<count; i++)
//	{
//	    if(i2c_write_core(ucData[i]) == 0)
//	    {
//	        return 0;
//	    }
//	}
//
//	i2c_stop();
//	return 1;
//}
